use core::{mem::MaybeUninit, ops::Deref};
use stm32f1::stm32f103::{dma1, dma2};


#[repr(align(8))]
pub struct DmaBuf<T, const SIZE: usize> {
    buf: MaybeUninit<[T; SIZE]>,
}

impl<T, const SIZE: usize> DmaBuf<T, SIZE> {

    #[inline(always)]
    pub const fn size(&self) -> usize {
        SIZE
    }
    
    #[inline(always)]
    pub const fn default() -> Self {
        Self { buf: MaybeUninit::uninit() }
    }

    #[inline(always)]
    pub const fn as_ref(&self) -> &[T] {
        unsafe { self.buf.assume_init_ref() }
    }

    pub const fn as_ptr(&self) -> *const T {
        self.buf.as_ptr() as *const T
    }

    pub fn slice(&self, begin: usize, len: usize) -> &[T] {
        let buf = self.as_ref();
        &buf[begin..(begin + len)]
    }

    pub fn as_slice(&self, len: usize) -> &[T] {
        let buf = self.as_ref();
        &buf[..len]
    }

    #[inline(always)]
    pub fn as_mut_ref(&mut self) -> &mut [T] {
        unsafe { self.buf.assume_init_mut() }
    }
}

pub struct DMA1;
pub struct DMA2;

impl Deref for DMA1 {
    type Target = dma1::RegisterBlock;
    fn deref(&self) -> &Self::Target {
        unsafe { &*stm32f1::stm32f103::DMA1::PTR }
    }
}

impl Deref for DMA2 {
    type Target = dma2::RegisterBlock;
    fn deref(&self) -> &Self::Target {
        unsafe { &*stm32f1::stm32f103::DMA2::PTR }
    }
}

